package edu.pku.sei.mte.transformation.gt;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import edu.pku.sei.mte.mtemodel.model.MModelGraph;
import edu.pku.sei.mte.mtemodel.mtmodel.Transformation;
import edu.pku.sei.mte.mtemodel.mtmodel.rulebased.RBTransformation;
import edu.pku.sei.mte.mtemodel.mtmodel.rulebased.Relation;
import edu.pku.sei.mte.mtemodel.mtmodel.rulebased.Rule;
import edu.pku.sei.mte.runtime.Context;
import edu.pku.sei.mte.runtime.rulebased.RBTContext;
import edu.pku.sei.mte.runtime.rulebased.RBTEnvironment;

public class GTEnforceVisitor extends GTSemanticVisitor {

	public GTEnforceVisitor(RBTEnvironment env) {
		super(env);
	}

	@Override
	public Object visitRelation(Relation e) throws Exception {
		List<Context> contexts = new ArrayList<Context>();
		getSemantic().gtFindContext(e, getContextStack().peek(), contexts, false);
		return getSemantic().gtEnforceRelation(e, getContextStack().peek().getEnvironment(), contexts);
	}

	@Override
	public Object visitTransformation(Transformation e) throws Exception {
		List<Rule> rules = ((RBTransformation) e).getRules();
		//reorder the rules according to the priority
		Collections.sort(rules, new Comparator<Rule>(){
			public int compare(Rule o1, Rule o2) {
				if(o1.getPriority()<0&&o2.getPriority()>=0)
					return o2.getPriority();
				if(o2.getPriority()<0&&o1.getPriority()>=0)
					return o1.getPriority();
				
				return o1.getPriority()-o2.getPriority();
			}
			
		});
		
		MModelGraph targetModel = this.getEnv().getModelGraph(getEnv().getTarget());
		int count = 0;
		do{
			targetModel.resetChangeState();
			for(Rule r : rules){
				if(r.getPriority()<0)
					continue;
				RBTContext context = getEnv().createNewContext();
				r.registVariableToContext(context);
				getContextStack().push(context);
				System.out.println("Enforce Rule "+r.getName());
				r.accept(this);
				System.out.println("Rule " + r.getName() + " passed");
				getContextStack().pop();
			}
			count++;//record round no.
			
		}while(targetModel.isGraphChange());
		return Boolean.TRUE;
	}

}
